﻿using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Threading;
using SharpDX.XAudio2;

namespace XAudio2Controls
{
   
    [DisplayName("XAudio2 Status Bar")]
    [Description("Provides updates on XAudio2 PerformanceData Properties.")]
    [ToolboxItem(true)]
    [TemplatePart(Name = "XAudio2_StatusBar", Type = typeof(StatusBar))]
    public class XAudio2StatusBar : Control, INotifyPropertyChanged
    {

        #region Delegates

        public delegate void CheckBoxdelegate();

        #endregion Delegates
        #region Fields
        //private CheckBoxdelegate chkBxDel = new CheckBoxdelegate();
        private DispatcherTimer _timer;
        //private int num = 0;
        internal static XAudio2 engine;
        StatusBar xAudio2StatusBar;
        StatusBarItem statusBarPanel1;
        Menu statusselect;
        List<StatusBarItem> StatusBarItems;
        StatusBarItem p_ActiveSourceVoiceCount;
        StatusBarItem p_MemoryUsageInBytes;
        StatusBarItem p_CurrentLatencyInSamples;
        StatusBarItem p_ActiveMatrixMixCount;
        StatusBarItem p_AudioCyclesSinceLastQuery;
        StatusBarItem p_TotalCyclesSinceLastQuery;
        StatusBarItem p_MaximumCyclesPerQuantum;
        StatusBarItem p_MinimumCyclesPerQuantum;
        StatusBarItem p_GlitchesSinceEngineStarted;
        StatusBarItem p_TotalSourceVoiceCount;
        StatusBarItem p_ActiveSubmixVoiceCount;
        StatusBarItem p_ActiveResamplerCount;
        StatusBarItem p_ActiveXmaSourceVoices;
        StatusBarItem p_ActiveXmaStreams;
        private int activesourcevoicecount;
        private int memoryusageinbytes;
        private int currentlatencyinsamples;
        private int activematrixmixcount;
        private long audiocyclessincelastquery;
        private long totalcyclessincelastquery;
        private int maximumcyclesperquantum;
        private int minimumcyclesperquantum;
        private int glitchessinceenginestarted;
        private int totalsourcevoicecount;
        private int activesubmixvoicecount;
        private int activeresamplercount;
        private int activexmasourcevoices;
        private int activexmastreams;
        MenuItem m_ActiveSourceVoiceCount;
        MenuItem m_MemoryUsageInBytes;
        MenuItem m_CurrentLatencyInSamples;
        MenuItem m_ActiveMatrixMixCount;
        MenuItem m_AudioCyclesSinceLastQuery;
        MenuItem m_TotalCyclesSinceLastQuery;
        MenuItem m_MaximumCyclesPerQuantum;
        MenuItem m_MinimumCyclesPerQuantum;
        MenuItem m_GlitchesSinceEngineStarted;
        MenuItem m_TotalSourceVoiceCount;
        MenuItem m_ActiveSubmixVoiceCount;
        MenuItem m_ActiveResamplerCount;
        MenuItem m_ActiveXmaSourceVoices;
        MenuItem m_ActiveXmaStreams;
        Thread workerThread;
        #endregion

        #region properties


        #region Performance Data
        public int ActiveSourceVoiceCount
        {
            get
            {
                return activesourcevoicecount;
            }
            set
            {

                activesourcevoicecount = engine.PerformanceData.ActiveSourceVoiceCount;
                NotifyPropertyChanged("ActiveSourceVoiceCount");
            }
        }

        public int MemoryUsageInBytes
        {
            get
            {
                return memoryusageinbytes;
            }
            set
            {
                memoryusageinbytes = engine.PerformanceData.MemoryUsageInBytes;
                NotifyPropertyChanged("MemoryUsageInBytes");
            }
        }

        public int CurrentLatencyInSamples
        {
            get
            {
                return currentlatencyinsamples;
            }
            set
            {
                currentlatencyinsamples = engine.PerformanceData.CurrentLatencyInSamples;
                NotifyPropertyChanged("CurrentLatencyInSamples");
            }
        }

        public int ActiveMatrixMixCount
        {
            get
            {
                return activematrixmixcount;
            }
            set
            {
                activematrixmixcount = engine.PerformanceData.ActiveMatrixMixCount;
                NotifyPropertyChanged("ActiveMatrixMixCount");
            }
        }

        public long AudioCyclesSinceLastQuery
        {
            get { return audiocyclessincelastquery; }
            set
            {
                audiocyclessincelastquery = engine.PerformanceData.AudioCyclesSinceLastQuery;
                NotifyPropertyChanged("AudioCyclesSinceLastQuery");
            }
        }

        public long TotalCyclesSinceLastQuery
        {
            get { return totalcyclessincelastquery; }
            set
            {
                totalcyclessincelastquery = (int)engine.PerformanceData.TotalCyclesSinceLastQuery;
                NotifyPropertyChanged("TotalCyclesSinceLastQuery");
            }
        }

        public int MaximumCyclesPerQuantum
        {
            get { return maximumcyclesperquantum; }
            set
            {
                maximumcyclesperquantum = engine.PerformanceData.MaximumCyclesPerQuantum;
                NotifyPropertyChanged("MaximumCyclesPerQuantum");
            }
        }

        public int MinimumCyclesPerQuantum
        {
            get { return minimumcyclesperquantum; }
            set
            {
                minimumcyclesperquantum = engine.PerformanceData.MinimumCyclesPerQuantum;
                NotifyPropertyChanged("MinimumCyclesPerQuantum");
            }
        }

        public int GlitchesSinceEngineStarted
        {
            get { return glitchessinceenginestarted; }
            set
            {
                glitchessinceenginestarted = engine.PerformanceData.GlitchesSinceEngineStarted;
                NotifyPropertyChanged("GlitchesSinceEngineStarted");
            }
        }

        public int TotalSourceVoiceCount
        {
            get
            {
                return totalsourcevoicecount;
            }
            set
            {
                totalsourcevoicecount = engine.PerformanceData.TotalSourceVoiceCount;
                NotifyPropertyChanged("TotalSourceVoiceCount");
            }
        }

        public int ActiveSubmixVoiceCount
        {
            get { return activematrixmixcount; }
            set
            {
                activesubmixvoicecount = engine.PerformanceData.ActiveSubmixVoiceCount;
                NotifyPropertyChanged("ActiveSubmixVoiceCount");
            }
        }

        public int ActiveResamplerCount
        {
            get { return activeresamplercount; }
            set
            {
                activeresamplercount = engine.PerformanceData.ActiveResamplerCount;
                NotifyPropertyChanged("ActiveResamplerCount");
            }
        }

        public int ActiveXmaSourceVoices
        {
            get { return activexmasourcevoices; }
            set
            {
                activexmasourcevoices = engine.PerformanceData.ActiveXmaSourceVoices;
                NotifyPropertyChanged("ActiveXmaSourceVoices");
            }
        }

        public int ActiveXmaStreams
        {
            get { return activexmastreams; }
            set
            {
                activexmastreams = engine.PerformanceData.ActiveXmaStreams;
                NotifyPropertyChanged("ActiveXmaStreams");
            }
        }

        #endregion

        public FrameworkElement ResourceRoot
        {
            get { return GetTemplateChild("LayoutRoot") as FrameworkElement; }
        }

        #endregion

        #region Constructors

        static XAudio2StatusBar()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(XAudio2StatusBar), new FrameworkPropertyMetadata(typeof(XAudio2StatusBar)));
        }

        public XAudio2StatusBar(XAudio2 _engine)
        {
            
            engine = _engine;
            _timer = new DispatcherTimer();
            this.PropertyChanged += stats_PropertyChanged;
            Initialize_Field_StatusBarItems();
            startTimer();
        }

        #endregion

        #region Methods
        /// <summary>
        /// not in use
        /// </summary>
        private void StartWorkerThread()
        {
            workerThread = new Thread(new ThreadStart(ThreadDoWork));
            workerThread.SetApartmentState(ApartmentState.STA);
            workerThread.Start();
        }
        private void ThreadDoWork()
        {
            _timer = new DispatcherTimer();
            this.PropertyChanged += stats_PropertyChanged;
            Initialize_Field_StatusBarItems();
            startTimer();
        }

        private long GetMyValue(string Match)
        {
            switch (Match)
            {
                case "ActiveSourceVoiceCount":
                    return ActiveSourceVoiceCount;
                case "MemoryUsageInBytes":
                    return MemoryUsageInBytes;
                case "CurrentLatencyInSamples":
                    return CurrentLatencyInSamples;
                case "ActiveMatrixMixCount":
                    return ActiveMatrixMixCount;
                case "AudioCyclesSinceLastQuery":
                    return AudioCyclesSinceLastQuery;
                case "TotalCyclesSinceLastQuery":
                    return TotalCyclesSinceLastQuery;
                case "MaximumCyclesPerQuantum":
                    return MaximumCyclesPerQuantum;
                case "MinimumCyclesPerQuantum":
                    return MaximumCyclesPerQuantum;
                case "GlitchesSinceEngineStarted":
                    return GlitchesSinceEngineStarted;
                case "TotalSourceVoiceCount":
                    return TotalSourceVoiceCount;
                case "ActiveSubmixVoiceCount":
                    return ActiveSubmixVoiceCount;
                case "ActiveResamplerCount":
                    return ActiveResamplerCount;
                case "ActiveXmaSourceVoices":
                    return ActiveXmaSourceVoices;
                case "ActiveXmaStreams":
                    return ActiveXmaStreams;
                default:
                    return 0;
            }
        }

        private static string[] GetPerformanceDataProperties()
        {
            string[] PerformanceDataProperties = new string[]
        {
        "ActiveSourceVoiceCount",
        "MemoryUsageInBytes",
        "CurrentLatencyInSamples",
        "ActiveMatrixMixCount",

        "AudioCyclesSinceLastQuery",
        "TotalCyclesSinceLastQuery",
        "MaximumCyclesPerQuantum",
        "MinimumCyclesPerQuantum",
        "GlitchesSinceEngineStarted",
        "TotalSourceVoiceCount",
        "ActiveSubmixVoiceCount",
        "ActiveResamplerCount",
        "ActiveXmaSourceVoices",
        "ActiveXmaStreams",
        };
            return PerformanceDataProperties;
        }

        private void RefreshPerformanceDataProperties()
        {
            try
            {
                if (engine == null)
                    throw new XAudio2ControlsException("no Xaudio2 Engine");

                if (ActiveSourceVoiceCount != engine.PerformanceData.ActiveSourceVoiceCount)
                    ActiveSourceVoiceCount = engine.PerformanceData.ActiveSourceVoiceCount;

                if (MemoryUsageInBytes != engine.PerformanceData.MemoryUsageInBytes)
                    MemoryUsageInBytes = engine.PerformanceData.MemoryUsageInBytes;

                if (CurrentLatencyInSamples != engine.PerformanceData.CurrentLatencyInSamples)
                    CurrentLatencyInSamples = engine.PerformanceData.CurrentLatencyInSamples;

                if (ActiveMatrixMixCount != engine.PerformanceData.ActiveMatrixMixCount)
                    ActiveMatrixMixCount = engine.PerformanceData.ActiveMatrixMixCount;

                if (AudioCyclesSinceLastQuery != engine.PerformanceData.AudioCyclesSinceLastQuery)
                    AudioCyclesSinceLastQuery = engine.PerformanceData.ActiveMatrixMixCount;

                if (TotalCyclesSinceLastQuery != engine.PerformanceData.TotalCyclesSinceLastQuery)
                    TotalCyclesSinceLastQuery = engine.PerformanceData.TotalCyclesSinceLastQuery;

                if (MaximumCyclesPerQuantum != engine.PerformanceData.MaximumCyclesPerQuantum)
                    MaximumCyclesPerQuantum = engine.PerformanceData.MaximumCyclesPerQuantum;

                if (MinimumCyclesPerQuantum != engine.PerformanceData.MinimumCyclesPerQuantum)
                    MinimumCyclesPerQuantum = engine.PerformanceData.MinimumCyclesPerQuantum;

                if (GlitchesSinceEngineStarted != engine.PerformanceData.GlitchesSinceEngineStarted)
                    GlitchesSinceEngineStarted = engine.PerformanceData.GlitchesSinceEngineStarted;

                if (TotalSourceVoiceCount != engine.PerformanceData.TotalSourceVoiceCount)
                    TotalSourceVoiceCount = engine.PerformanceData.TotalSourceVoiceCount;

                if (ActiveSubmixVoiceCount != engine.PerformanceData.ActiveSubmixVoiceCount)
                    ActiveSubmixVoiceCount = engine.PerformanceData.ActiveSubmixVoiceCount;

                if (ActiveResamplerCount != engine.PerformanceData.ActiveResamplerCount)
                    ActiveResamplerCount = engine.PerformanceData.ActiveResamplerCount;

                if (ActiveXmaSourceVoices != engine.PerformanceData.ActiveXmaSourceVoices)
                    ActiveXmaSourceVoices = engine.PerformanceData.ActiveXmaSourceVoices;

                if (ActiveXmaStreams != engine.PerformanceData.ActiveXmaStreams)
                  ActiveXmaStreams = engine.PerformanceData.ActiveXmaStreams;

                
            }
            catch (XAudio2ControlsException ex)
            {
                _timer.Stop();
                System.Windows.MessageBox.Show(ex.ToString());
            }
        }

        #endregion

        #region Private Construction Methods

        private void startTimer()
        { 
            _timer.Interval = TimeSpan.FromMilliseconds(1000);
            _timer.Tick += new EventHandler(_timer_Tick);
            _timer.Start();
        }

         /// <summary>
        ///The object that holds the objects that this menu displays.
        ///If the menu items are not contained in another intermediary MenuItem, they wont
        ///open in a seperate menu.  Instead, they will all be awkardly clustered
        ///on the status bar itself.
        /// </summary>
        private void buildMenu()
        {
            statusselect = PutMenuItemsInParentMenu(GetMenuItems());

            xAudio2StatusBar.Items.Add(statusselect);

            foreach (StatusBarItem s in StatusBarItems)
            {
                xAudio2StatusBar.Items.Add(s);
            }
        }

        private void Initialize_Field_StatusBarItems()
        {
            StatusBarItems = new List<StatusBarItem>();

            foreach (StatusBarItem sbi in GetStatusBarItems())
            {
                StatusBarItems.Add(sbi);
            }

            //StartWorkerThread();
            //ThreadDoWork();
        }

        private StatusBarItem[] GetStatusBarItems()
        { 

        StatusBarItem[] statusbaritemarray = 
            {
             p_ActiveSourceVoiceCount = new StatusBarItem()
            {
                DataContext = ActiveSourceVoiceCount,
                Uid = "ActiveSourceVoiceCount",
                Tag = ActiveSourceVoiceCount,
                Content = DataContext,
                IsEnabled = true,
            },    
            p_MemoryUsageInBytes = new StatusBarItem()
            {
                DataContext = MemoryUsageInBytes,
                Uid = "MemoryUsageInBytes",
                Tag = MemoryUsageInBytes,
                Content = DataContext,
                IsEnabled = true,
            },
            p_ActiveMatrixMixCount = new StatusBarItem()
            {
                DataContext = ActiveMatrixMixCount,
                Uid = "ActiveMatrixMixCount",
                Tag = ActiveMatrixMixCount,
                Content = DataContext,
                IsEnabled = true,
            },
            p_CurrentLatencyInSamples = new StatusBarItem()
            {
                DataContext = CurrentLatencyInSamples,
                Uid = "CurrentLatencyInSamples",
                Tag = CurrentLatencyInSamples,
                Content = DataContext,
                ContentStringFormat =ToString(),
                IsEnabled = true,
            },
            p_AudioCyclesSinceLastQuery = new StatusBarItem()
            {
                DataContext = AudioCyclesSinceLastQuery,
                Uid = "AudioCyclesSinceLastQuery",
                Tag = AudioCyclesSinceLastQuery,
                Content = DataContext,
                ContentStringFormat = ToString(),
                IsEnabled = false
            },
            p_TotalCyclesSinceLastQuery = new StatusBarItem()
            {
                DataContext = TotalCyclesSinceLastQuery,
                Uid = "TotalCyclesSinceLastQuery",
                Tag = TotalCyclesSinceLastQuery,
                Content = DataContext,
                ContentStringFormat = ToString(),
                IsEnabled = false
            },
            p_MaximumCyclesPerQuantum = new StatusBarItem()
            {
                DataContext = MaximumCyclesPerQuantum,
                Uid = "MaximumCyclesPerQuantum",
                Tag = MaximumCyclesPerQuantum,
                Content = DataContext,
                ContentStringFormat = ToString(),
                IsEnabled = false
            },
            p_MinimumCyclesPerQuantum = new StatusBarItem()
            {
                DataContext = MinimumCyclesPerQuantum,
                Uid = "MaximumCyclesPerQuantum",
                Tag = MinimumCyclesPerQuantum,
                Content = DataContext,
                ContentStringFormat = ToString(),
                IsEnabled = false
            },
            p_GlitchesSinceEngineStarted = new StatusBarItem()
            {
                DataContext = GlitchesSinceEngineStarted,
                Uid = "GlitchesSinceEngineStarted",
                Tag = GlitchesSinceEngineStarted,
                Content = DataContext,
                ContentStringFormat = ToString(),
                IsEnabled = false
            },
            p_TotalSourceVoiceCount = new StatusBarItem()
            {
                DataContext = TotalSourceVoiceCount,
                Uid = "TotalSourceVoiceCount",
                Tag = TotalSourceVoiceCount,
                Content = DataContext,
                IsEnabled = false
            },
            p_ActiveSubmixVoiceCount = new StatusBarItem()
            {
                DataContext = ActiveSubmixVoiceCount,
                Uid = "ActiveSubmixVoiceCount",
                Tag = ActiveSubmixVoiceCount,
                Content = DataContext,
                IsEnabled = false
            },
            p_ActiveResamplerCount = new StatusBarItem()
            {
                DataContext = ActiveResamplerCount,
                Uid = "ActiveResamplerCount",
                Tag = ActiveResamplerCount,
                Content = DataContext,
                IsEnabled = false
            },
            p_ActiveXmaSourceVoices = new StatusBarItem()
            {
                DataContext = ActiveXmaSourceVoices,
                Uid = "ActiveXmaSourceVoices",
                Tag = ActiveXmaSourceVoices,
                Content = DataContext,
                IsEnabled = false
            },
            p_ActiveXmaStreams = new StatusBarItem()
            {
                DataContext = ActiveXmaStreams,
                Uid = "ActiveXmaStreams",
                Tag = ActiveXmaStreams,
                Content = DataContext,
                IsEnabled = false
            },
            
        
            };

        return statusbaritemarray;
        }

        private MenuItem[] GetMenuItems()
        {
            MenuItem[] menuitems =
            {
            m_ActiveSourceVoiceCount = new MenuItem()
            {
                
                Header = "ActiveSourceVoiceCount",
            IsCheckable=true, 
            IsChecked=true,
            StaysOpenOnClick=true
            },
            m_MemoryUsageInBytes = new MenuItem()
            {
                
                Header = "MemoryUsageInBytes",
            IsCheckable=true, 
            IsChecked=true,
            StaysOpenOnClick=true
            },
            m_CurrentLatencyInSamples = new MenuItem()
            {
                
                Header = "CurrentLatencyInSamples",
            IsCheckable=true, 
            IsChecked=true,
            StaysOpenOnClick=true
            },
            m_ActiveMatrixMixCount = new MenuItem()
            {
                
                Header = "ActiveMatrixMixCount",
            IsCheckable=true, 
            IsChecked=true,
            StaysOpenOnClick=true
            },
            m_AudioCyclesSinceLastQuery = new MenuItem()
            {
                
                Header = "AudioCyclesSinceLastQuery",
            IsCheckable=true, 
            IsChecked=false,
            StaysOpenOnClick=true
            },
            m_TotalCyclesSinceLastQuery = new MenuItem()
            {
                
                Header = "TotalCyclesSinceLastQuery",
            IsCheckable=true, 
            IsChecked=false,
            StaysOpenOnClick=true
            },
            m_MaximumCyclesPerQuantum = new MenuItem()
            {
                
                Header = "MaximumCyclesPerQuantum",
            IsCheckable=true, 
            IsChecked=false,
            StaysOpenOnClick=true
            },
            m_MinimumCyclesPerQuantum = new MenuItem()
            {
                
                Header = "MinimumCyclesPerQuantum",
            IsCheckable=true, 
            IsChecked=false,
            StaysOpenOnClick=true
            },
            m_GlitchesSinceEngineStarted = new MenuItem()
            {
                
                Header = "GlitchesSinceEngineStarted",
            IsCheckable=true, 
            IsChecked=false,
            StaysOpenOnClick=true
            },
            m_TotalSourceVoiceCount = new MenuItem()
            {
                
                Header = "TotalSourceVoiceCount",
            IsCheckable=true, 
            IsChecked=false,
            StaysOpenOnClick=true
            },
            m_ActiveSubmixVoiceCount = new MenuItem()
            {
                
                Header = "ActiveSubmixVoiceCount",
            IsCheckable=true, 
            IsChecked=false,
            StaysOpenOnClick=true
            },
            m_ActiveResamplerCount = new MenuItem()
            {
                
                Header = "ActiveResamplerCount",
            IsCheckable=true, 
            IsChecked=false,
            StaysOpenOnClick=true
            },
            m_ActiveXmaSourceVoices = new MenuItem()
            {
                
                Header = "ActiveXmaSourceVoices",
            IsCheckable=true, 
            IsChecked=false,
            StaysOpenOnClick=true
            },
            m_ActiveXmaStreams = new MenuItem()
            {
                
                Header = "ActiveXmaStreams",
            IsCheckable=true, 
            IsChecked=false,
            StaysOpenOnClick=true
            },
        };
            return menuitems;
        }

        private Menu PutMenuItemsInParentMenu(MenuItem[] menuItems)
        {
            statusselect = new Menu();

            MenuItem middleManMenuItem = new MenuItem()
            {
                Header = "DisplayedStats",
            };

            foreach (MenuItem mi in menuItems)
            {
                middleManMenuItem.Items.Add(mi);
                mi.Checked += DisplayedStatsItem_Checked;
                mi.Unchecked += DisplayedStatsItem_Checked;
            }

            statusselect.Items.Add(middleManMenuItem);

            return statusselect;

           
        }

        private void GetTemplateChildren()
        {
            
                xAudio2StatusBar = ResourceRoot.FindName("XAudio2_StatusBar") as StatusBar;
                statusselect = ResourceRoot.FindName("statussselect") as Menu;
                statusBarPanel1 = ResourceRoot.FindName("statusBarPanel1") as StatusBarItem;
                NotifyPropertyChanged("HasTemplateChildren");             
        }

        #endregion methods

        #region Event Overrides

        public override void OnApplyTemplate()
        {
            if (xAudio2StatusBar == null)
            {
                GetTemplateChildren();
                buildMenu();
            }
        }
        #endregion

        #region Event Handlers

        void stats_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {           
            foreach (StatusBarItem s in StatusBarItems)
            {               
                if (e.PropertyName.ToString() == s.Uid)
                {
                    if (s.IsEnabled == true)
                        s.Content = "[ " + s.Uid + " " + GetMyValue(e.PropertyName) + " ]";
                    if (s.IsEnabled == false)
                        s.Content = null;
                    break;
                }
            }  
        }
        private void DisplayedStatsItem_Checked(object sender, RoutedEventArgs e)
        {
            var theSender = sender as System.Windows.Controls.MenuItem;
            foreach (StatusBarItem s in StatusBarItems)
            {
                if (theSender.Header.ToString() == s.Uid)
                {
                    switch (s.IsEnabled)
                    { 
                        case true:
                            s.IsEnabled = false;
                            break;
                        case false:
                            s.IsEnabled = true;
                            break;
                    }
                   // s.IsEnabled = true;
                   // break;
                }
            }
        }

        void _timer_Tick(object sender, EventArgs e)
        {
            RefreshPerformanceDataProperties();
        }

        #endregion

        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(null, new PropertyChangedEventArgs(info));
            }
        }
        #endregion
    }
}
